"""
Copyright 2012 Wieser Dietmar, Margit Mutschlechner.

This file is part of Multimedia Social Networking Platform.

Multimedia Social Networking Platform is free software: 
you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Multimedia Social Networking Platform is distributed
in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Multimedia Social Networking Platform.  
If not, see <http://www.gnu.org/licenses/>.

"""

from threading import Thread
from msnp.service.network import NetworkLock, NetworkController, \
    AuthenticationValidator, CustodyQueue, BackupController
from msnp.logger import Logger
from msnp.service.network.logic import MessageExchangeLogic, ResponsibilityLogic
from msnp.persistence import PersistenceController
from msnp.model.PTPModel import BackupContent
from msnp.model import PTPModel

##########################
## execute remote calls ##
##########################

def authenticate(identity, isLogin):
    """This function is used for the authentication process.
    
    Checks whether this is still the responsible peer for the PeerInfo instance (network could have changed since this responsible peer was found).
    If this is still the responsible peer all login credentials (username and password) are checked depending on whether its a login or a register request.
    The new PeerInfo instance gets added to the list of low level peers.
    An authentication-message gets stored for the new peer and the backup gets updated.
    If this is no more the responsible peer a new search will be started.
    
    Args:
        identity: The new PeerInfo instance of the authenticating peer.
        isLogin: This boolean determines whether the new peer initiated a login or a registration.
    """
    
    #lock because other low level peer could upgrade shortly before -> this peer is not included in that shift 
    NetworkLock.acquireJoinLock()
    try:
        newIdentityHashedNameLong = identity.getHashedNameLong()
        #if I am not responsible I am the entry peer and search for the responsible peer
        if ResponsibilityLogic.amIResponsibleIdentityFor(newIdentityHashedNameLong) == False:
            Logger.info("not responsible to authenticate peer " + identity.getName() + ", re-hello him")
            MessageExchangeLogic.executeHello(identity, isLogin)
        #if I am responsible I check the credentials, add him as low level peer, store an authentication-message for him and update my fingers
        else:
            validationType = AuthenticationValidator.validateAuthentication(identity, isLogin)
            receiverName = identity.getName()
            CustodyQueue.addAuthMessage(receiverName, validationType)
            if validationType == PTPModel.ReturnType.SUCCESSFUL:
                # add all stored messages to the custody queue (he will process only those with processed=False)
                storedMessages = PersistenceController.selectMessagesForUsername(receiverName, False)
                if storedMessages != None:
                    Logger.info("add " + str(len(storedMessages)) + " not processed msg to custody queue")
                    CustodyQueue.addCustodyMessages(storedMessages)
                
                NetworkController.getMySelf().addLowLevelPeer(receiverName, identity)
                myName = NetworkController.getMySelf().getMyIdentity().getName()
                user = PersistenceController.selectUserImResponsibleForUsername(identity.getName())
                backupContent = BackupContent(myName, [user], None, None, PTPModel.BackupType.UPDATE)
                BackupController.updateBackupAtFingers(backupContent)
                Logger.info("peer " + identity.getName() + " authenticated")
            else:
                Logger.info("Validation of peer " + identity.getName() + " was not successful!!!!")
    finally:
        NetworkLock.releaseJoinLock()


##############################
## threads for remote calls ##
##############################

class AuthenticationThread(Thread):
    """Authentication thread.

    Attributes:
        __identity: The new PeerInfo instance of the authenticating peer.
        __isLogin: This boolean determines whether the new peer initiated a login or a registration.
    """
    
    def __init__(self, identity, isLogin):
        """the init method"""
        Thread.__init__(self)
        self.__identity = identity
        self.__isLogin = isLogin
        
    def run(self):
        """This method forwards the call to the authenticate function."""
        authenticate(self.__identity, self.__isLogin)
        

#####################
## execute threads ##
#####################

def executeAuthenticate(identity, isLogin):
    """This function starts an authentication thread.
    
    Args:
        identity: The new PeerInfo instance of the authenticating peer.
        isLogin: This boolean determines whether the new peer initiated a login or a registration.
    """
    authThread = AuthenticationThread(identity, isLogin)
    authThread.start()
